﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Nirvana
{
    public class FindComponentEditor : EditorWindow
    {
        MonoScript targetScript;
        Vector2 scrollPos = new Vector2(0, 0);

        GameObject selectTargetGameObject;
        GameObject hightLightTarget;

        string jumpPage = "1";
        int pageNum = 1;
        int row = 15;                   //行
        List<Dictionary<GameObject, GameObject>> dirList = new List<Dictionary<GameObject, GameObject>>();
        string searchPath = "Assets/Resources";
        public static void Open()
        {
            FindComponentEditor myWindow = (FindComponentEditor)EditorWindow.GetWindow(typeof(FindComponentEditor), false, "查找组件引用");
            myWindow.Show();
        }

        private void OnGUI()
        {
            EditorGUILayout.Space();
            targetScript = EditorGUILayout.ObjectField("添加组件:", targetScript, typeof(MonoScript), true) as MonoScript;
            GUILayout.Space(20);
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PrefixLabel("查找路径:");
            searchPath = EditorGUILayout.TextArea(searchPath);
            EditorGUILayout.EndHorizontal();
            GUILayout.Space(20);
            EditorGUILayout.BeginHorizontal();
            #region 批量查找
            if (GUILayout.Button("开始查找"))
            {
                if (targetScript == null)
                {
                    this.ShowNotification(new GUIContent("请放入组件!!!!"));
                }
                else
                {
                    pageNum = 1;
                    selectTargetGameObject = null;
                    hightLightTarget = null;
                    dirList.Clear();

                    FindAllQuote();
                }
            }
            #endregion

            #region 批量删除
            if (GUILayout.Button("批量删除"))
            {
                if (targetScript == null)
                {
                    this.ShowNotification(new GUIContent("请放入组件!!!!"));
                }
                else
                {
                    selectTargetGameObject = null;
                    hightLightTarget = null;

                    AllDelete();
                }
            }
            #endregion
            EditorGUILayout.EndHorizontal();

        
            #region 查找结果
            if (dirList != null && dirList.Count > 0)
            {
                var maxPage = dirList.Count;
                if (pageNum > maxPage)
                {
                    pageNum = maxPage;
                }

                var nowList = dirList[pageNum - 1];
                scrollPos = EditorGUILayout.BeginScrollView(scrollPos);

                foreach (var dic in nowList)
                {
                    string str = dic.Value.name;
                    if (dic.Key != dic.Value)
                    {
                        str = str + " 的 " + dic.Key.name;
                    }
                    #region 点击对应的标签后触发
                    var editorStyle = EditorStyles.helpBox;
                    if (hightLightTarget != null && hightLightTarget == dic.Key)
                    {
                        editorStyle = EditorStyles.objectFieldThumb;
                        //str = str + "    (当前选择!!!!!)";
                    }
                    if (GUILayout.Button(str, editorStyle, GUILayout.Height(20f)))
                    {
                        var realPreafabList = GetRealPreafabList();

                        selectTargetGameObject = null;
                        hightLightTarget = null;
                        #region 查找场景中符合的prefab
                        foreach (var realPrefab in realPreafabList)
                        {
                            //获取场景上这个prefab在project中的原始prefab
                            var target = PrefabUtility.GetPrefabParent(realPrefab);
                            if (target != null && target == dic.Value)
                            {
                                var target_obj = dic.Key;
                                string path = target_obj.name;
                                Transform newTransForm = target_obj.transform;
                                while (newTransForm.parent != null && newTransForm.parent.parent != null)
                                {
                                    //获取这个节点在prefab上的路径（不包括root节点）
                                    newTransForm = newTransForm.parent;
                                    path = string.Format("{0}/{1}", newTransForm.name, path);
                                }
                                if (path != target_obj.name || newTransForm.parent != null)
                                {
                                    selectTargetGameObject = realPrefab.transform.Find(path).gameObject;
                                }
                                else
                                {
                                    selectTargetGameObject = realPrefab;
                                }
                                break;
                            }
                        }
                        #endregion
                        if (selectTargetGameObject == null)
                        {
                            //直接获取资源目录中的prefab
                            selectTargetGameObject = dic.Value;
                        }
                        //根据Object指引对应的位置
                        EditorGUIUtility.PingObject(selectTargetGameObject);
                        Selection.activeObject = selectTargetGameObject;
                        hightLightTarget = dic.Key;
                    }
                    #endregion
                }

                EditorGUILayout.EndScrollView();

                #region 翻页
                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("上一页"))
                {
                    if (pageNum <= 1)
                    {
                        pageNum = 1;
                        return;
                    }
                    pageNum--;
                }

                GUIStyle ta_guiStyle = new GUIStyle(GUI.skin.textArea);
                ta_guiStyle.normal.textColor = Color.white;
                ta_guiStyle.alignment = TextAnchor.MiddleCenter;
                ta_guiStyle.fontSize = 15;
                EditorGUILayout.LabelField(pageNum + " / " + maxPage, ta_guiStyle);

                if (GUILayout.Button("下一页"))
                {
                    if (pageNum >= maxPage)
                    {
                        pageNum = maxPage;
                        return;
                    }
                    pageNum++;
                }
                EditorGUILayout.EndHorizontal();

                GUILayout.Space(5);

                EditorGUILayout.BeginHorizontal();
                var t_guiStyle = new GUIStyle(GUI.skin.textArea);
                t_guiStyle.normal.textColor = Color.white;
                t_guiStyle.alignment = TextAnchor.MiddleCenter;
                t_guiStyle.fontSize = 15;
                jumpPage = EditorGUILayout.TextField(jumpPage, t_guiStyle);
                if (GUILayout.Button("跳转"))
                {
                    int jump_num = 1;
                    try
                    {
                        jump_num = int.Parse(jumpPage);

                        if (jump_num < 1 || jump_num > maxPage)
                        {
                            return;
                        }
                        pageNum = jump_num;
                    }
                    catch (Exception)
                    {
                        ShowNotification(new GUIContent("输数字！"));
                    }
                }
                EditorGUILayout.EndHorizontal();
                #endregion

                GUILayout.Space(5);
            }
            #endregion
   
        }

        void FindAllQuote()
        {
            var assets = AssetDatabase.FindAssets("t:prefab",new string[] { searchPath });
            int startIndex = 0;
            int maxLength = assets.Length;
            using (ProgressIndicator progress = new ProgressIndicator("generate asset keys", maxLength))
            {
                for (int i = startIndex; i < maxLength; i++)
                {
                    var guid = assets[i];
                    var path = AssetDatabase.GUIDToAssetPath(guid);

                    progress.SetProgress(i);
                    progress.ShowForce("check asset:{0}", path);

                    var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                    if (prefab != null)
                    {
                        var components = prefab.transform.GetComponentsInChildren(targetScript.GetClass(), true);
                        foreach (var component in components)
                        {
                            if (!CheckHasKey(component.gameObject))
                            {
                                AddItem(component.gameObject, prefab.gameObject);
                            }
                        }
                    }
                }
            }

        }

        void AllDelete()
        {
            var assets = AssetDatabase.FindAssets("t:prefab",new string[] { searchPath });
            int startIndex = 0;
            int max_length = assets.Length;

            for (int i = startIndex; i < max_length; i++)
            {
                var guid = assets[i];
                var path = AssetDatabase.GUIDToAssetPath(guid);

                var cancel = EditorUtility.DisplayCancelableProgressBar("匹配资源中", path, (float)i / max_length);
                if (cancel)
                {
                    break;
                }

                var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                if (prefab != null)
                {
                    var components = prefab.transform.GetComponentsInChildren(targetScript.GetClass(), true);
                    foreach (var component in components)
                    {
                        RemoveKey(component.gameObject);
                        DestroyImmediate(component, true);
                    }
                }
                else
                {
                    Debug.LogError("未知错误，无法找到prefab");
                }
            }
            EditorUtility.ClearProgressBar();
            AssetDatabase.SaveAssets();
            this.Repaint();
        }

        //获取场景上存在的所有用户自定义的prefab实例
        List<GameObject> GetRealPreafabList()
        {
            List<GameObject> realPreafabList = new List<GameObject>();

            //获取当前激活的场景.
            Scene scene = SceneManager.GetActiveScene();
            //获取场景上所有父级的GameObject.
            var objs = scene.GetRootGameObjects();

            foreach (var obj in objs)
            {
                if (PrefabUtility.GetPrefabType(obj) == PrefabType.PrefabInstance)
                {
                    //找到了直接添加到表里，不再继续通过该节点深入查找
                    realPreafabList.Add(obj);
                }
                else
                {
                    Queue<GameObject> queue = new Queue<GameObject>();
                    queue.Enqueue(obj);
                    while (queue.Count > 0)
                    {
                        bool is_add = false;
                        var new_obj = queue.Dequeue();
                        if (PrefabUtility.GetPrefabType(new_obj) == PrefabType.PrefabInstance)
                        {
                            realPreafabList.Add(new_obj);
                            is_add = true;
                        }
                        if (!is_add)
                        {
                            for (int i = 0; i < new_obj.transform.childCount; ++i)
                            {
                                var child = new_obj.transform.GetChild(i);
                                queue.Enqueue(child.gameObject);
                            }
                        }
                    }
                }
            }

            //Debug.LogError(realPreafabList.Count);
            return realPreafabList;
        }

        bool CheckHasKey(GameObject key)
        {
            var count = dirList.Count;
            for (int i = 0; i < count; i++)
            {
                var dic = dirList[i];
                if (dic.ContainsKey(key))
                {
                    return true;
                }
            }
            return false;
        }

        void AddItem(GameObject key, GameObject value)
        {
            if (dirList.Count <= 0)
            {
                var new_dic = new Dictionary<GameObject, GameObject>();
                new_dic.Add(key, value);
                dirList.Add(new_dic);
            }
            else
            {
                var last_dic = dirList[dirList.Count - 1];
                if (last_dic.Count >= row)
                {
                    var new_dic = new Dictionary<GameObject, GameObject>();
                    new_dic.Add(key, value);
                    dirList.Add(new_dic);
                }
                else
                {
                    last_dic.Add(key, value);
                }
            }
        }
        void RemoveKey(GameObject key)
        {
            var count = dirList.Count;
            for (int i = 0; i < count; i++)
            {
                var dic = dirList[i];
                dic.Remove(key);
                if (dic.Count <= 0)
                {
                    dirList.Remove(dic);
                }
            }
        }

    }
}

